iT邦幫忙

2021 iThome 鐵人賽

DAY 17
2
自我挑戰組

【Side Project】 系列 第 17

【Side Project】 點菜單功能實作 - 資料庫新增餐點清單

  • 分享至 

  • xImage
  •  

寫到資料庫這部分,就讓我想起一個小故事...

某天客戶一把鼻涕一把眼淚地打電話跟我說
客戶: 我們要結帳了,可是有些單子裡面的項目有少怎麼辦?
這不查不打緊,一查才發現,客戶公司有一陣子網路不穩定,
轉資料的時候,常常轉到一半網路掛掉,導致某些時段的單子的資料只轉了一半。
看完資料後我也只想說.....涼拌炒雞蛋,愈炒愈完蛋。

很多剛開始做開發的新人常常會將SQL語法拆開來,很單純的一個命令一個命令送,
導致我們很難去判別,每一筆(交易)資料是否完整。
若想解決這個問題,我們可以透過資料庫ACID特性中的原子性(Atomicity),
來達到確保每筆資料的完整。

新建 Data Class

建立需要與資料庫的Table相對應的Class
https://ithelp.ithome.com.tw/upload/images/20210930/20115941iasVR1bsS9.jpg
Menulistb.cs

public class Menulistb
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public long Uid { get; set; }
        public long H_uid { get; set; }
        public string Item { get; set; }
        public int Price { get; set; }
        public int Count { get; set; }
    }

Menulisth.cs

public class Menulisth
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public long Uid { get; set; }
        public string Formnum { get; set; }
        [SugarColumn(IsOnlyIgnoreInsert = true)]
        public int Createtime { get; set; }
    }

這邊要注意Createtime上給的屬性**[SugarColumn(IsOnlyIgnoreInsert = true)]**
因為我們之後會直接從資料庫給這個欄位default值,所以需要設立這個屬性。

資料庫欄位設定預設值

  1. 開啟SSMS
  2. 輸入SQL語法
  ALTER TABLE [dbo].[menulisth]
  ADD CONSTRAINT DF_Menulisth_Createtime
  DEFAULT CURRENT_TIMESTAMP FOR [createtime]

https://ithelp.ithome.com.tw/upload/images/20210930/20115941IbInfV62FM.jpg
這樣每當我們新增一筆資料的時候,就會自動把當下時間帶入到createtime裡面。

接收前台的資料

上一篇中已經把資料從前端送到後端來了,
我們接著把傳過來的資料處理一下轉成對應的object。
1.將 傳過來的data 轉成 object

Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);

從Json轉成Object 無非就四樣:

  1. Dictionary( key,value 類)
  2. List(清單類)
  3. base type (基本資料型態)
  4. Data Class (自訂類)

稍微注意一下資料的結構就會轉了。
2. 把剛剛上面那段加入我們後台處理問題的function中 CreateOrder()

public ActionResult CreateOrder(string data,string phone)
        {
        // 表頭部分資料
             var menulisth = new Menulisth()
            {
                Formnum = phone
            };
            Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
            return Ok();
        }

寫入資料庫

  1. 建立資料庫連線
//連線設定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                //連線字串
                ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WebMenu;user id=webmenu;password=xxxxxxxx;Integrated Security=False",
                DbType = DbType.SqlServer,//連線類型
                IsAutoCloseConnection = true //自動關閉連線
            });
  1. try...catch包起來我們等等要寫入資料庫的基本框架
try
            {
                
                //當執行時,觸發事件
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//查看SQL語法
                };
                db.BeginTran();
                // dosomething
                db.CommitTran();
            }
            catch 
            {
                db.RollbackTran();//rollback
                throw;
            }

當我們資料出問題的時候會退回到原本的狀態,並且打印我們SQL語法的資訊
3. 在 dosomething 的地方寫我們要寫入資料庫的語法

db.BeginTran();
                //寫入表頭 並 回傳表頭資料
                menulisth = db.Insertable(menulisth).ExecuteReturnEntity();
                //逐筆將表身資料寫入
                foreach (var keyvalue in map)
                {
                    var item = keyvalue.Value;
                    Console.WriteLine(item.Uid + " : " + item.Item + " : " + item.Price + " : " + item.Count);
                    item.H_uid = menulisth.Uid;
                    db.Insertable(item).ExecuteCommand();
                }
                
                db.CommitTran();

這樣就成功將資料寫入我們資料庫了。
CreateOrder()中完整程式碼:

public ActionResult CreateOrder(string data,string phone)
        {
            var menulisth = new Menulisth()
            {
                Formnum = phone
            };
            Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
            
            //連線設定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                //連線字串
                ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WebMenu;user id=webmenu;password=xxxxxxxx;Integrated Security=False",
                DbType = DbType.SqlServer,//連線類型
                IsAutoCloseConnection = true //自動關閉連線
            });
            try
            {
                
                //當執行時,觸發事件
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//查看SQL語法
                };
                db.BeginTran();
                //寫入表頭 並 回傳表頭資料
                menulisth = db.Insertable(menulisth).ExecuteReturnEntity();
                //逐筆將表身資料寫入
                foreach (var keyvalue in map)
                {
                    var item = keyvalue.Value;
                    Console.WriteLine(item.Uid + " : " + item.Item + " : " + item.Price + " : " + item.Count);
                    item.H_uid = menulisth.Uid;
                    db.Insertable(item).ExecuteCommand();
                }
                
                db.CommitTran();
            }
            catch 
            {
                db.RollbackTran();//rollback
                throw;
            }
            return Ok();
        }
  1. 建立一張餐點
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941d5nFXSx8UU.jpg
  2. 資料庫資料
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941yJ4dYn5Vy2.jpg
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941uBJNKBooMS.jpg

結語

我們可以透過 begin tran ... commit tran將所有要完成的指令一次做完,
這樣可以保證我們資料每次進入資料庫的時候都是完整的。

另外可能有些人會對時間資訊應該要由資料庫直接產生好,還是從程式碼中產生好的疑問。
這邊給一個思考的方向,當程式碼成長到上萬行,表單變成上千個的時候,
放在程式碼中,還是資料庫裡哪個比較好維護?


上一篇
【Side Project】 點菜單功能實作 - 前台資料傳到後台
下一篇
【Side Project】 程式碼整理 -Model運用
系列文
【Side Project】 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言